#pragma once

#include"Common.h"

namespace Macro
{
	const int SPEND_TYPE_AMOUNT = 11;

	enum SpendType
	{
		Hatchery,
		Lair,
		Spawning_Pool,
		Extractor,
		Hydralisk_Den,

		Drone,
		Zergling,
		Hydralisk,
		Overlord,
		Lurker,

		Lurker_Aspect,

		Larva,

		Undefined
	};

	enum SpendTypeCategory{Build , CreateUnit , Research , Upgrade};
	enum SpendMethod{Morph , Make};

	class SpendTypeInfo
	{
	public:
		//--
		SpendTypeInfo()
			:_unitType(UnitTypes::None)
		{
		}
		SpendTypeInfo(
			SpendTypeCategory category,
			UnitType unitType,
			TechType techType,
			int amountLimit,
			bool needInstance,
			int mineralPrice,
			int gasPrice,
			int supplyRequired,
			int supplyProvided,
			int frameNeeded,
			vector<SpendType>& requires,
			vector<SpendType>& enables,
			SpendType whatMakes,
			SpendType morphBy,
			int bornAmount,
			SpendMethod spendMethod,
			bool isArmy
			)
			:_category(category),
			_unitType(unitType),
			_techType(techType),
			_amountLimit(amountLimit),
			_needInstance(needInstance),
			_mineralPrice(mineralPrice),
			_gasPrice(gasPrice),
			_supplyRequired(supplyRequired),
			_supplyProvided(supplyProvided),
			_frameNeeded(frameNeeded),
			_requires(requires),
			_enables(enables),
			_whatMakes(whatMakes),
			_morphBy(morphBy),
			_bornAmount(bornAmount),
			_spendMethod(spendMethod),
			_isArmy(isArmy)
		{
		}
		void operator=(const SpendTypeInfo& another)
		{
			_category = another._category;
			_unitType = another._unitType;
			_techType = another._techType;
			_amountLimit = another._amountLimit;
			_needInstance = another._needInstance;
			_mineralPrice = another._mineralPrice;
			_gasPrice = another._gasPrice;
			_supplyRequired = another._supplyRequired;
			_supplyProvided = another._supplyProvided;
			_frameNeeded = another._frameNeeded;
			_requires = another._requires;
			_enables = another._enables;
			_whatMakes = another._whatMakes;
			_morphBy = another._morphBy;
			_bornAmount = another._bornAmount;
			_spendMethod = another._spendMethod;
		}
		inline const SpendTypeCategory& GetCategory() const
		{
			return _category;
		}
		inline const UnitType& GetUnitType() const
		{
			return _unitType;
		}
		inline const TechType& GetTechType() const
		{
			return _techType;
		}
		inline const int GetAmountLimit() const
		{
			return _amountLimit;
		}
		inline bool NeedInstance() const
		{
			return _needInstance;
		}
		inline const int GetMineralPrice() const
		{
			return _mineralPrice;
		}
		inline const int GetGasPrice() const
		{
			return _gasPrice;
		}
		inline const int GetSupplyRequired() const
		{
			return _supplyRequired;
		}
		inline const int GetSupplyProvided() const
		{
			return _supplyProvided;
		}
		inline const int GetFrameNeeded() const
		{
			return _frameNeeded;
		}
		inline const vector<SpendType>& GetRequires() const
		{
			return _requires;
		}
		inline const vector<SpendType>& GetEnables() const
		{
			return _enables;
		}
		inline const SpendType& WhatMakes() const
		{
			return _whatMakes;
		}
		inline const SpendType& MorphBy() const
		{
			return _morphBy;
		}
		inline const int GetBornAmount() const
		{
			return _bornAmount;
		}
		inline const SpendMethod& GetSpendMethod() const
		{
			return _spendMethod;
		}
		inline bool IsArmy() const
		{
			return _isArmy;
		}
	private:
		SpendTypeCategory _category;
		UnitType _unitType;
		TechType _techType;
		int _amountLimit;
		bool _needInstance;
		int _mineralPrice;
		int _gasPrice;
		int _supplyRequired;
		int _supplyProvided;
		int _frameNeeded;
		vector<SpendType> _requires;
		vector<SpendType> _enables;
		SpendType _whatMakes;
		SpendType _morphBy;
		int _bornAmount;
		SpendMethod _spendMethod;
		bool _isArmy;
	};

	SpendTypeInfo SpendTypeInfoTable[999];
	SpendType UnitTypeToMiniSpendTypeTable[999];
	SpendType TechTypeToMiniSpendTypeTable[999];
	vector<SpendType> TechnologySpendTypes;

	void InitUnitTypeToMiniSpendTypeTable()
	{
		for(int i = 0; i < 999 ; ++i)
		{
			UnitTypeToMiniSpendTypeTable[i] = Undefined;
		}

		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Hatchery] = Hatchery;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Lair] = Lair;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Spawning_Pool] = Spawning_Pool;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Extractor] = Extractor;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Hydralisk_Den] = Hydralisk_Den;

		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Drone] = Drone;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Zergling] = Zergling;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Hydralisk] = Hydralisk;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Lurker] = Lurker;

		UnitTypeToMiniSpendTypeTable[UnitTypes::None] = Undefined;
		UnitTypeToMiniSpendTypeTable[UnitTypes::Zerg_Larva] = Undefined;
	}

	void InitSpendTypeTable()
	{
		InitUnitTypeToMiniSpendTypeTable();
		TechnologySpendTypes.push_back(Lurker_Aspect);


		//Hatchery
		SpendTypeInfoTable[Hatchery] = SpendTypeInfo(Build , UnitTypes::Zerg_Hatchery , TechTypes::None , 3 , true ,
			300 , 0 , 0 , 2 , UnitTypes::Zerg_Hatchery.buildTime() ,
			vector<SpendType>() , vector<SpendType>() , Undefined , Drone , 1 , Morph , false);

		//Lair
		vector<SpendType> lairRequires;
		lairRequires.push_back(Extractor);
		lairRequires.push_back(Spawning_Pool);
		vector<SpendType> lairEnables;
		lairEnables.push_back(Lurker_Aspect);
		SpendTypeInfoTable[Lair] = SpendTypeInfo(Build , UnitTypes::Zerg_Lair , TechTypes::None , 1 , true ,
			UnitTypes::Zerg_Lair.mineralPrice() , UnitTypes::Zerg_Lair.gasPrice() , 0 , 2 , UnitTypes::Zerg_Lair.buildTime() ,
			lairRequires , lairEnables , Undefined , Hatchery , 1 , Morph , false);

		//Spawning_Pool
		vector<SpendType> spawningPoolEnables;
		spawningPoolEnables.push_back(Zergling);
		SpendTypeInfoTable[Spawning_Pool] = SpendTypeInfo(Build , UnitTypes::Zerg_Spawning_Pool , TechTypes::None , 1 , true ,
			200 , 0 , 0 , 0 , UnitTypes::Zerg_Spawning_Pool.buildTime() , 
			vector<SpendType>() , spawningPoolEnables , Undefined , Drone , 1 , Morph , false);

		//Extractor
		vector<SpendType> extractorEnables;
		extractorEnables.push_back(Hydralisk_Den);
		extractorEnables.push_back(Hydralisk);
		extractorEnables.push_back(Lair);
		extractorEnables.push_back(Lurker);
		extractorEnables.push_back(Lurker_Aspect);
		SpendTypeInfoTable[Extractor] = SpendTypeInfo(Build , UnitTypes::Zerg_Extractor , TechTypes::None , 1 , false , 
			50 , 0 , 0 , 0 , UnitTypes::Zerg_Extractor.buildTime() , 
			vector<SpendType>() , extractorEnables , Undefined , Drone , 1 , Morph , false);

		//Hydralisk_Den
		vector<SpendType> hydraliskDenRequires;
		hydraliskDenRequires.push_back(Extractor);
		hydraliskDenRequires.push_back(Spawning_Pool);
		vector<SpendType> hydraliskDenEnables;
		hydraliskDenEnables.push_back(Hydralisk);
		hydraliskDenEnables.push_back(Lurker_Aspect);
		SpendTypeInfoTable[Hydralisk_Den] = SpendTypeInfo(Build , UnitTypes::Zerg_Hydralisk_Den , TechTypes::None , 1 , true , 
			UnitTypes::Zerg_Hydralisk_Den.mineralPrice() , UnitTypes::Zerg_Hydralisk_Den.gasPrice() , 0 , 0 , UnitTypes::Zerg_Extractor.buildTime() , 
			hydraliskDenRequires , hydraliskDenEnables , Undefined , Drone , 1 , Morph , false);

		//Drone
		SpendTypeInfoTable[Drone] = SpendTypeInfo(CreateUnit , UnitTypes::Zerg_Drone , TechTypes::None , 999 , false , 
			50 , 0 , 2 , 0 , UnitTypes::Zerg_Drone.buildTime() , 
			vector<SpendType>() , vector<SpendType>() , Undefined , Larva , 1 , Morph , true);

		//Zergling
		vector<SpendType> zerglingRequires;
		zerglingRequires.push_back(Spawning_Pool);
		SpendTypeInfoTable[Zergling] = SpendTypeInfo(CreateUnit , UnitTypes::Zerg_Zergling , TechTypes::None , 999 , false , 
			50 , 0 , 1 , 0 , UnitTypes::Zerg_Zergling.buildTime() , 
			zerglingRequires , vector<SpendType>() , Undefined , Larva , 2 , Morph , true);

		//Hydralisk
		vector<SpendType> hydraliskRequires;
		hydraliskRequires.push_back(Extractor);
		hydraliskRequires.push_back(Hydralisk_Den);
		SpendTypeInfoTable[Hydralisk] = SpendTypeInfo(CreateUnit , UnitTypes::Zerg_Hydralisk , TechTypes::None , 999 , false , 
			75 , 25 , 2 , 0 , UnitTypes::Zerg_Hydralisk.buildTime() , 
			hydraliskRequires , vector<SpendType>() , Undefined , Larva , 1 , Morph , true);


		//Overlord
		SpendTypeInfoTable[Overlord] = SpendTypeInfo(CreateUnit , UnitTypes::Zerg_Overlord , TechTypes::None , 999 , false , 
			100 , 0 , 0 , 16 , UnitTypes::Zerg_Overlord.buildTime() , 
			vector<SpendType>() , vector<SpendType>() , Undefined , Larva , 1 , Morph , false);

		//Lurker
		vector<SpendType> lurkerRequires;
		lurkerRequires.push_back(Extractor);
		lurkerRequires.push_back(Lurker_Aspect);
		SpendTypeInfoTable[Lurker] = SpendTypeInfo(CreateUnit , UnitTypes::Zerg_Lurker , TechTypes::None , 999 , false , 
			50 , 100 , 4 , 0 , UnitTypes::Zerg_Lurker.buildTime() , 
			lurkerRequires , vector<SpendType>() , Undefined , Hydralisk , 1 , Morph , true);


		//Lurker_Aspect
		vector<SpendType> lurkerAspectRequires;
		lurkerAspectRequires.push_back(Extractor);
		lurkerAspectRequires.push_back(Lair);
		vector<SpendType> lurkerAspectEnables;
		lurkerAspectEnables.push_back(Hydralisk);
		SpendTypeInfoTable[Lurker] = SpendTypeInfo(Research , UnitTypes::None , TechTypes::Lurker_Aspect , 1 , false , 
			200 , 200 , 0 , 0 , TechTypes::Lurker_Aspect.researchTime() , 
			lurkerAspectRequires , lurkerAspectEnables , Hydralisk_Den , Undefined , 1 , Make , false);

	}

	//============================

	inline const SpendType& GetSpendType(const UnitType& unitType)
	{
		return UnitTypeToMiniSpendTypeTable[unitType];
	}

	inline const SpendType& GetSpendType(const TechType& techType)
	{
		return TechTypeToMiniSpendTypeTable[techType];
	}

	inline const SpendTypeCategory GetCategory(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetCategory();
	}

	inline const UnitType& GetUnitType(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetUnitType();
	}

	inline const TechType& GetTechType(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetTechType();
	}

	//-------------------------------

	inline const int AmountLimit(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetAmountLimit();
	}

	inline bool NeedInstance(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].NeedInstance();
	}

	inline const int MineralPrice(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetMineralPrice();
	}

	inline const int GasPrice(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetGasPrice();
	}

	inline const int SupplyRequired(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetSupplyRequired();
	}

	inline const int SupplyProvided(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetSupplyProvided();
	}

	inline const int FrameNeeded(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetFrameNeeded();
	}

	inline const vector<SpendType>& GetRequires(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetRequires();
	}

	inline const vector<SpendType>& GetEnables(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetEnables();
	}

	inline const SpendType& WhatMakes(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].WhatMakes();
	}

	inline const SpendType& OriginalSpendType(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].MorphBy();
	}

	inline const int BornAmount(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetBornAmount();
	}

	inline const SpendMethod& GetSpendMethod(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].GetSpendMethod();
	}

	inline bool IsArmy(const SpendType& spendType)
	{
		return SpendTypeInfoTable[spendType].IsArmy();
	}
}